package crontab

import (
	"encoding/json"
	"longmen/server/config/global"
	"longmen/server/internal/rpc/tencentim/imsdk"
	"longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/db/mysql"
	"longmen/server/pkg/db/mysql/db_guess"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_guess"
	"longmen/server/pkg/db/redis/cache"
	"math"
	"time"

	"github.com/spf13/cast"
	"longmen/server/pkg/common/api_models"
)

// 开奖 退奖
func SettleGuess() { //首先得到一个封盘了的竞猜
	var err error
	var delta int
	cache.WriteOdds(_const.GUESS_STATUS_CLOSED)
	cache.WriteOdds(_const.GUESS_STATUS_SETTLED)
	cache.WriteOdds(_const.GUESS_ORDER_INIT)
	oGuessList := make([]*models_guess.Guess, 0, 0)
	oOrderList := make([]*models_guess.GuessOrder, 0, 0)
	var settle_one_order = func(gorder *models_guess.GuessOrder, guess *models_guess.Guess, iDelta int, consumeType int) error {
		iCode, err := db_guess.ProcessSettleOrder(gorder, guess, iDelta, consumeType) //处理一个订单
		if err != nil {
			global.Log.Errorf("6SettleGuess9%v", err)
		}
		if iCode > 0 {
			cache.DelUserFullCache(gorder.Uid)
		}
		//20221111这里改为，如果某一场的订单开奖完了， 那就把这一场开奖完的信息告诉给客户端，然后客户端再请求得到单个人的中奖信息
		/*err = cache.SendGuessPrompt(gorder, models_guess, gorder.ReceiveUid)//原有的，是给单个用户推通知
		if err != nil {
			global.Log.Errorf("6SettleGuess9%v", err)
		}*/
		return err
	}
	var send_settled_msg = func(guess *models_guess.Guess, orderList []*models_guess.GuessOrder) {
		var arrUid []string
		for _, v := range orderList {
			arrUid = append(arrUid, cast.ToString(v.Uid))
		}
		oMsg := api_models.MessageGuessSettled{
			Type:    "guessSettled",
			GuessId: guess.Id,
		}
		sMsg, _ := json.Marshal(oMsg)
		global.Log.Debugf("settled msg to send:%s|%+v", sMsg, arrUid)

		imsdk.GetSdk().BatchSendUser(arrUid, string(sMsg))
	}
	var f_settle = func(guessStatus int, guessPayStatus int, guessPayStatusFinish int,
		arrOrderStatus []int) {
		var mParam = map[string]interface{}{"status": guessStatus, "pay_status": guessPayStatus}
		if guessStatus == _const.GUESS_STATUS_SETTLED { //如果是已开奖的，结果不能为0啊
			mParam["result"] = map[string]interface{}{"<>": 0}
		}
		db_guess.GetGuessAnyListParam(&models_guess.Guess{}, &oGuessList,
			mParam, "GetSettledGuessList", "", 0, 0)
		var nOrder int64
		for _, vGuess := range oGuessList { //场次列表
			//从主数据库拿订单
			mysql.CountXAnyParam(&models_guess.GuessOrder{}, &nOrder,
				map[string]interface{}{"guess_id": vGuess.Id,
					"status": map[string]interface{}{"in": arrOrderStatus}},
				"CountGuessOrder", "", "", 0, 0)
			if nOrder == 0 {
				vGuess.PayStatus = guessPayStatusFinish //没有列表了，那就记为finish的状态（场次已结算）
				vGuess.UpdateTime = time.Now()
				err := db_guess.UpdateGuessAnyWithId(nil, []string{"pay_status", "update_time"}, vGuess, "settleGuessPaid")
				if err != nil {
					global.Log.Errorf("settleGuessPaid%v", err)
				}
				continue
			}
			nMaxUserCount := 500
			nErrCount := 0
			for iPage := 1; iPage <= int(nOrder)/nMaxUserCount+1; iPage++ {
				mysql.GetXAnyListParam(&models_guess.GuessOrder{}, &oOrderList,
					map[string]interface{}{"guess_id": vGuess.Id,
						"status": map[string]interface{}{"in": arrOrderStatus}},
					"SettleGuess_OrderList", "", iPage, nMaxUserCount) //订单列表

				aOdds := util.String2FloatArray(vGuess.Odds, vGuess.ItemNum)       //??已开奖又没有赔率
				if guessStatus == _const.GUESS_STATUS_SETTLED && len(aOdds) == 0 { //派奖必须要有赔率和结果
					global.Log.Errorf("6settleGuess9invalid odds or res%v", err)
					continue
				}

				for _, vOrder := range oOrderList {
					if guessStatus == _const.GUESS_STATUS_SETTLED { //派奖
						if vOrder.GuessItem == vGuess.Result &&
							vOrder.GuessItem-1 >= 0 && vOrder.GuessItem <= len(aOdds) {
							vOrder.Profit = int(aOdds[vOrder.GuessItem-1] * float64(vOrder.Amount) / 100) //算奖哦
							vOrder.Status = _const.GUESS_ORDER_WIN
							vOrder.PayStatus = _const.GUESS_PAY_PAID
							vOrder.Odds = int(aOdds[vOrder.GuessItem-1])
						} else { //没中奖 或投注项无效
							vOrder.Profit = 0
							vOrder.Status = _const.GUESS_ORDER_MISSED
							vOrder.PayStatus = _const.GUESS_PAY_PAID
							vOrder.UpdateTime = time.Now()
						}
						err = settle_one_order(vOrder, vGuess, vOrder.Profit, _const.PROFIT_GUESS_WIN) //事务一条龙服务
					} else if guessStatus == _const.GUESS_STATUS_CANCELED || guessStatus == _const.GUESS_STATUS_INVALID { //取消
						vOrder.Status = _const.GUESS_ORDER_CANCELED //给大家退钱
						delta = vOrder.Amount                       //加钱
						vOrder.Profit = 0
						vOrder.PayStatus = _const.GUESS_PAY_CANCEL                                //改了以后就不会再被找到
						err = settle_one_order(vOrder, vGuess, delta, _const.PROFIT_GUESS_RETURN) //事务一条龙服务
					} else if guessStatus == _const.GUESS_STATUS_SETTLED_CANCELED { //派奖后取消
						if vOrder.Status == _const.GUESS_ORDER_MISSED || vOrder.Status == _const.GUESS_ORDER_INIT {
							vOrder.Status = _const.GUESS_ORDER_CANCELED //没中奖的直接退
							vOrder.PayStatus = _const.GUESS_PAY_PAID_CANCEL
							delta = vOrder.Amount                                                     //加钱
							err = settle_one_order(vOrder, vGuess, delta, _const.PROFIT_GUESS_RETURN) //事务一条龙服务
						} else if vOrder.Status == _const.GUESS_ORDER_WIN { //除了要扣掉profit - 本金那么多
							vOrder.Status = _const.GUESS_ORDER_CANCELED
							vOrder.PayStatus = _const.GUESS_PAY_PAID_CANCEL
							delta = -(vOrder.Profit - vOrder.Amount)
							if delta >= 0 {
								global.Log.Errorf("6settle9: wrong profit, %v", delta)
								continue //这里如果不用扣钱就跳过了
							}
							//看一下够不够钱，不够钱只把他所有的余额扣掉
							bEnough, iBalance, err := db_main.UserHasEnoughMoney(uint(vOrder.Uid),
								uint(math.Abs(float64(delta))), int(_const.CoinGold))
							if err != nil {
								global.Log.Errorf("settle: %v", err)
								continue
							}
							if !bEnough {
								delta = -1 * int(iBalance) //钱不够那就有多少扣多少呗
							}
							err = settle_one_order(vOrder, vGuess, delta, _const.CONSUME_GUESS_CANCEL_WIN)
						}
					} //end if 订单不同类型判断
					if err != nil {
						global.Log.Errorf("6SettleOrder9:%v", err)
						nErrCount++
					}

				} //end for 遍历单页订单
				if guessStatus == _const.GUESS_STATUS_SETTLED { //新状态为开奖，那就给大家发消息通知
					send_settled_msg(vGuess, oOrderList)
				}
			} //end for 遍历count
			if nErrCount == 0 {
				vGuess.PayStatus = guessPayStatusFinish //没有列表了，那就记为finish的状态（场次已结算）
				vGuess.UpdateTime = time.Now()
				cache.PrepareMsgUpdateGuessStatus(vGuess.LiveId, true)
				err := db_guess.UpdateGuessAnyWithId(nil, []string{"pay_status", "update_time"}, vGuess, "settleGuessPaid")
				if err != nil {
					global.Log.Errorf("settleGuessPaid%v", err)
				}
			}

		} //end for 遍历竞猜
	}
	f_settle(_const.GUESS_STATUS_SETTLED, _const.GUESS_PAY_NOT_PAID, _const.GUESS_PAY_PAID,
		[]int{_const.GUESS_ORDER_INIT}) //期次已开奖 + 订单未开奖
	f_settle(_const.GUESS_STATUS_CANCELED, _const.GUESS_PAY_NOT_PAID, _const.GUESS_PAY_PAID,
		[]int{_const.GUESS_ORDER_INIT, _const.GUESS_ORDER_WIN, _const.GUESS_ORDER_MISSED})
	//期次已取消 + 订单未开奖or 订单已开奖 or 订单未中奖
	f_settle(_const.GUESS_STATUS_INVALID, _const.GUESS_PAY_NOT_PAID, _const.GUESS_PAY_PAID,
		[]int{_const.GUESS_ORDER_INIT}) //期次已无效 + 订单未开奖
	f_settle(_const.GUESS_STATUS_SETTLED_CANCELED, _const.GUESS_PAY_NOT_PAID, _const.GUESS_PAY_PAID,
		[]int{_const.GUESS_ORDER_INIT, _const.GUESS_ORDER_WIN, _const.GUESS_ORDER_MISSED}) //期次派奖后取消 + 订单未开奖 or 订单已派奖 or 订单未中奖

}

/*
这个方法是用来发送限流的消息，特点是如果有很多条进来，每次只发最新的一条
*/
func HardFreshGuessStatus() {
	/*这一块是生成quiz假数据
	sliceInfo := make([]*api_models.GuessInfo, 0)
	sliceInfo = append(sliceInfo, &api_models.GuessInfo{
		GId:     1,
		QId:     2,
		LiveId:  3,
		Title:   "Air raid. Pearl Harbor. This is no drill.",
		Content: timehelper.Now().Format("2006-02-01 15:04:05"),
	})
	cache.WsMsgWithInterval(6010875, 6010875, sliceInfo, "quiz")
	/**/

	mList, err := cache.GetGuessList()
	global.Log.Debugf("hard refresh models_guess list:%+v", mList)
	if err != nil || mList == nil {
		return
	} else {
		for _, v := range *mList {
			err = cache.PrepareMsgUpdateGuessStatus(v, true)
			if err != nil {
				global.Log.Warnf("hard fresh err:%s", err.Error())
			}
		}
	}
}

/*
**
定时器，每次要执行完一轮后才会进入下一轮
*/
func SettleGuessTimer(iInterval int) {
	for {
		time.Sleep(time.Duration(iInterval) * time.Second)
		global.Log.Debug(">>>>>settling models_guess orders")
		SettleGuess()
		global.Log.Debug("<<<<<<finished models_guess orders")
	}
}
func SendGuessUpdate() {
	iCounter := 0
	for {
		time.Sleep(500 * time.Millisecond) //每500毫秒check一次
		iCounter++
		if iCounter >= 60 { //每隔一段时间去刷新缓存
			iCounter = 0
			HardFreshGuessStatus()
		}
		mList, err := cache.GetGuessList()
		if err != nil || mList == nil {
			continue
		} else {
			for k := range *mList {
				//给各个房间update赔率消息
				info, err := cache.GetAndDelGuessStatusMsgForRoom(k)
				if err != nil || len(info) == 0 {
					continue
				}
				oMsg := api_models.GuessStatusMsg{
					Type:    "quiz",
					Message: info,
				}
				global.Log.Debugf("msg to send:%+v", oMsg)
				imsdk.GetSdk().BroadcastInterface(k, oMsg, 3)
			}
		}
	}
}
